﻿/*------------------------------------------------------------------------

VERTEXRD.HPP v1.1.8

Copyright 楊志賢 CxxlMan, 2014
All Rights Reserved

------------------------------------------------------------------------*/

#if !defined(__VERTEXRD_HPP_Cxxl3D)
#define __VERTEXRD_HPP_Cxxl3D

#include <CRITICAL.HPP>
#include <Sys\RENDERUNIT.HPP>
#include <Sys\RenderUnit\SYSDDCLASSID.HPP>
#include <Sys\VERTEXFMT.HPP>
#include <Sys\CSMART_PTR.HPP>
#include <Sys\CSMART_ARRAY.HPP>

namespace Cxxl3D
{

// 指定格式的索引模式頂點集合，依索引模式可用來包裝 Strip 或 List 的排列方式
template <typename T>
class tagVertex
{
  CxxlMan::CriticalSec csObject;

  C3D_USINT m_VertexNum; // 頂點數目
  CxxlMan::CSmart_Array<const T> m_Vertex_Array;

  C3D_USINT m_IndexNum; // Index 數目
  CxxlMan::CSmart_Array<const C3D_USINT> m_Index_Array;

public:

  void cxxlFASTCALL LockVertex() const
  {
    csObject.Enter();
  }

  void cxxlFASTCALL UnLockVertex() const
  {
    csObject.Leave();
  }

  // Constructor
  tagVertex()
    :m_Vertex_Array(NULL),
    m_Index_Array(NULL)
  {
    m_VertexNum = 0;
    m_IndexNum = 0;
  }

  // Copy Constructor
  tagVertex(const tagVertex<T> &Src)
    :m_Vertex_Array(NULL),
    m_Index_Array(NULL)
  {
    Src.LockVertex();

    m_VertexNum = Src.m_VertexNum;
    m_IndexNum = Src.m_IndexNum;
    m_Vertex_Array = Src.m_Vertex_Array;
    m_Index_Array = Src.m_Index_Array;

    Src.UnLockVertex();
  }

  // Destructor
  ~tagVertex()
  {
  }

  // Assign
  tagVertex<T> & operator=(const tagVertex<T> &Src)
  {
    Src.LockVertex();

    C3D_USINT tmpVertexNum = Src.m_VertexNum;
    C3D_USINT tmpIndexNum = Src.m_IndexNum;

    CSmart_Array<const T> tmpVertex_Array = Src.m_Vertex_Array;
    CSmart_Array<const C3D_USINT> tmpIndex_Array = Src.m_Index_Array;

    Src.UnLockVertex();

    this->LockVertex();

    m_VertexNum = tmpVertexNum;
    m_IndexNum = tmpIndexNum;
    m_Vertex_Array = tmpVertex_Array;
    m_Index_Array = tmpIndex_Array;

    this->UnLockVertex();

    return *this;
  }

  void cxxlFASTCALL SetData(C3D_USINT VertexNum, const CxxlMan::CSmart_Array<const T> &Vertex_Array, C3D_USINT IndexNum, const CxxlMan::CSmart_Array<const C3D_USINT> &Index_Array)
  {
    this->LockVertex();

    m_VertexNum = VertexNum;
    m_IndexNum = IndexNum;
    m_Vertex_Array = Vertex_Array;
    m_Index_Array = Index_Array;

    this->UnLockVertex();
  }

  void cxxlFASTCALL GetData(C3D_USINT &VertexNum, CxxlMan::CSmart_Array<const T> &Vertex_Array, C3D_USINT &IndexNum,  CxxlMan::CSmart_Array<const C3D_USINT> &Index_Array) const
  {
    this->LockVertex();

    VertexNum = m_VertexNum;
    IndexNum = m_IndexNum;
    Vertex_Array = m_Vertex_Array;
    Index_Array = m_Index_Array;

    this->UnLockVertex();
  }
};



class IVertex:public IRenderDatagram, public DepositStore
{
protected:
  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && CxxlMan::cxxlPreserve2::Ref(F))
      return true;
    else
      return false;
  }

  // Constructor
  IVertex()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(L"") // 在建構時指定 ClassID
  {
  }

  // Destructor
  ~IVertex()
  {
  }

public:


  // 只有 DepositStore 有 SetDeposit 才能取得
  // 有取得回覆 true
  // virtual bool cxxlFASTCALL GetVertexIndexNum(C3D_USINT &VertexNum,  C3D_USINT &IndexNum) const = 0;

  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<IVertex>;  // Preserve2 元件須加上這個
};


template<typename VERTEXFMT>
class IVertexRD;


// 供 Render 要重新取得頂點資料時，藉由此介面取得
template<typename VERTEXFMT>
class IRetrieveVertex:virtual public CxxlMan::cxxlPreserve2
{


protected:
  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && CxxlMan::cxxlPreserve2::Ref(F))
      return true;
    else
      return false;
  }

  // Constructor
  IRetrieveVertex()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(L"") // 在建構時指定 ClassID
  {
  }

  // Destructor
  ~IRetrieveVertex()
  {
  }

public:

  // 須實作
  //virtual void cxxlFASTCALL GetVertex(const CxxlMan::Smart_Ptr< CxxlMan::delegate< const CxxlMan::CSmart_Ptr<const tagVertex<VERTEXFMT> > & > > &);

  // 須實作
  virtual void cxxlFASTCALL GetVertex(const CxxlMan::Smart_Ptr< IVertexRD<VERTEXFMT> > &);
};


template<typename VERTEXFMT>
class IVertexRD:public IVertex
{


protected:
  // 為這個頂點指定一個識別，作為須要取回頂點資料時可作為識別
  virtual void cxxlFASTCALL SysInit(const CxxlMan::UNICODE_String &VertexID) = 0;

  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && CxxlMan::cxxlPreserve2::Ref(F))
      return true;
    else
      return false;
  }

  // Constructor
  IVertexRD()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(L"") // 在建構時指定 ClassID
  {
  }

  // Destructor
  ~IVertexRD()
  {
  }
public:

  // 取得頂點資料識別，IRetrieveVertex 的實作須有能力藉此將正確的頂點資料由 SetVertexData() 置入
  virtual CxxlMan::UNICODE_String cxxlFASTCALL  GetVertexID() = 0;

  // 設定 tagVertex<> 資料
  virtual void cxxlFASTCALL SetVertexData(const CxxlMan::CSmart_Ptr<const tagVertex<VERTEXFMT> > &tagVertex_Arg) = 0;

  // 取得 tagVertex<> 資料
  virtual CxxlMan::CSmart_Ptr<const tagVertex<VERTEXFMT> > cxxlFASTCALL GetVertexData() const = 0;

  // 通知其儲存的 tagVertex<> 資料已被修改
  virtual void cxxlFASTCALL Modified() = 0;


  // 指示當 Render 單元取出頂點資料後，可以將之清除，內定是不清除的。
  // 須提供一個 IRetrieveVertex，作為須取回頂點資料時的處理方法
  // RetrieveVertex_Arg 不可為 NULL，否則 Crushable() 呼叫無效
  virtual void cxxlFASTCALL Crushable(const CxxlMan::Smart_Ptr<IRetrieveVertex<VERTEXFMT> > &RetrieveVertex_Arg) = 0;

  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<IVertexRD>;  // Preserve2 元件須加上這個
};


/******************************************************/


// 以 tagVERTEXFMT_NC 為頂點格式的索引式頂點陣列封裝
class IVertexRD_NC:public IVertexRD<tagVERTEXFMT_NC>
{
  // 這裡須傳回 IRenderDatagram 的 "實作介面"，即被 cxxlCM_GetElement() 叫用的 InterfaceID
  CxxlMan::UNICODE_String cxxlFASTCALL GetRenderDatagramID() const
  {
    return IVertex_NC_ClassID;
  }

  // 傳回 IRenderDatagram 的 "實作介面"
  virtual void *cxxlFASTCALL GetDefaultInterface()
  {
    return this;
  }

protected:
  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && IVertexRD::Ref(F))
      return true;
    else
      return false;
  }

  // Constructor
  IVertexRD_NC()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(IVertex_NC_ClassID) // 在建構時指定 ClassID
  {
  }

  // Destructor
  ~IVertexRD_NC()
  {
  }
public:


  // 建立 IVertexRD_NC 物件，失敗傳回 NULL
  // VertexID = 頂點資料識別
  static CxxlMan::Smart_Ptr<IVertexRD_NC> cxxlFASTCALL Create(const CxxlMan::UNICODE_String &VertexID)
  {
    CxxlMan::Smart_Ptr<IVertexRD_NC> r = CxxlMan::Preserve2_Cast<IVertexRD_NC>( CxxlMan::cxxlCM_GetElement(IVertex_NC_ClassID, IRenderDatagram_Group) );

    if(r.isNULL() == false)
      r->SysInit(VertexID);

    return r;
  }


  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<IVertexRD_NC>;  // Preserve2 元件須加上這個
};


/********************************************/


// 以 tagVERTEXFMT_C 為頂點格式的索引式頂點陣列封裝
class IVertexRD_C:public IVertexRD<tagVERTEXFMT_C>
{
  // 這裡須傳回 IRenderDatagram 的 "實作介面"，即被 cxxlCM_GetElement() 叫用的 InterfaceID
  CxxlMan::UNICODE_String cxxlFASTCALL GetRenderDatagramID() const
  {
    return IVertex_C_ClassID;
  }

  // 傳回 IRenderDatagram 的 "實作介面"
  virtual void *cxxlFASTCALL GetDefaultInterface()
  {
    return this;
  }

protected:
  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && IVertexRD::Ref(F))
      return true;
    else
      return false;
  }

  // Constructor
  IVertexRD_C()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(IVertex_C_ClassID) // 在建構時指定 ClassID
  {
  }

  // Destructor
  ~IVertexRD_C()
  {
  }
public:

  // 建立 IVertexRD_C 物件，失敗傳回 NULL
  // VertexID = 頂點資料識別
  static CxxlMan::Smart_Ptr<IVertexRD_C> cxxlFASTCALL Create(const CxxlMan::UNICODE_String &VertexID)
  {
    CxxlMan::Smart_Ptr<IVertexRD_C> r = CxxlMan::Preserve2_Cast<IVertexRD_C>( CxxlMan::cxxlCM_GetElement(IVertex_C_ClassID, IRenderDatagram_Group) );

    if(r.isNULL() == false)
      r->SysInit(VertexID);
    return r;
  }

  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<IVertexRD_C>;  // Preserve2 元件須加上這個
};

/********************************************/

// 以 tagVERTEXFMT_N 為頂點格式的索引式頂點陣列封裝
class IVertexRD_N:public IVertexRD<tagVERTEXFMT_N>
{
  // 這裡須傳回 IRenderDatagram 的 "實作介面"，即被 cxxlCM_GetElement() 叫用的 InterfaceID
  CxxlMan::UNICODE_String cxxlFASTCALL GetRenderDatagramID() const
  {
    return IVertex_N_ClassID;
  }

  // 傳回 IRenderDatagram 的 "實作介面"
  virtual void *cxxlFASTCALL GetDefaultInterface()
  {
    return this;
  }

protected:
  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && IVertexRD::Ref(F))
      return true;
    else
      return false;
  }

  // Constructor
  IVertexRD_N()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(IVertex_N_ClassID) // 在建構時指定 ClassID
  {
  }

  // Destructor
  ~IVertexRD_N()
  {
  }
public:

  // 建立 IVertexRD_N 物件，失敗傳回 NULL
  // VertexID = 頂點資料識別
  static CxxlMan::Smart_Ptr<IVertexRD_N> cxxlFASTCALL Create(const CxxlMan::UNICODE_String &VertexID)
  {
    CxxlMan::Smart_Ptr<IVertexRD_N> r = CxxlMan::Preserve2_Cast<IVertexRD_N>( CxxlMan::cxxlCM_GetElement(IVertex_N_ClassID, IRenderDatagram_Group) );

    if(r.isNULL() == false)
      r->SysInit(VertexID);
    return r;
  }

  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<IVertexRD_N>;  // Preserve2 元件須加上這個
};


/********************************************/

// 以 tagVERTEXFMT_NT 為頂點格式的索引式頂點陣列封裝
class IVertexRD_NT:public IVertexRD<tagVERTEXFMT_NT>
{
  // 這裡須傳回 IRenderDatagram 的 "實作介面"，即被 cxxlCM_GetElement() 叫用的 InterfaceID
  CxxlMan::UNICODE_String cxxlFASTCALL GetRenderDatagramID() const
  {
    return IVertex_NT_ClassID;
  }

  // 傳回 IRenderDatagram 的 "實作介面"
  virtual void *cxxlFASTCALL GetDefaultInterface()
  {
    return this;
  }

protected:
  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && IVertexRD::Ref(F))
      return true;
    else
      return false;
  }

  // Constructor
  IVertexRD_NT()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(IVertex_NT_ClassID) // 在建構時指定 ClassID
  {
  }

  // Destructor
  ~IVertexRD_NT()
  {
  }
public:

  // 建立 IVertexRD_NT 物件，失敗傳回 NULL
  // VertexID = 頂點資料識別
  static CxxlMan::Smart_Ptr<IVertexRD_NT> cxxlFASTCALL Create(const CxxlMan::UNICODE_String &VertexID)
  {
    CxxlMan::Smart_Ptr<IVertexRD_NT> r = CxxlMan::Preserve2_Cast<IVertexRD_NT>( CxxlMan::cxxlCM_GetElement(IVertex_NT_ClassID, IRenderDatagram_Group) );

    if(r.isNULL() == false)
      r->SysInit(VertexID);
    return r;
  }

  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<IVertexRD_NT>;  // Preserve2 元件須加上這個
};


/********************************************/
// 以 tagVERTEXFMT_T 為頂點格式的索引式頂點陣列封裝
class IVertexRD_T:public IVertexRD<tagVERTEXFMT_T>
{
  // 這裡須傳回 IRenderDatagram 的 "實作介面"，即被 cxxlCM_GetElement() 叫用的 InterfaceID
  CxxlMan::UNICODE_String cxxlFASTCALL GetRenderDatagramID() const
  {
    return IVertex_T_ClassID;
  }

  // 傳回 IRenderDatagram 的 "實作介面"
  virtual void *cxxlFASTCALL GetDefaultInterface()
  {
    return this;
  }

protected:
  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && IVertexRD::Ref(F))
      return true;
    else
      return false;
  }

  // Constructor
  IVertexRD_T()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(IVertex_T_ClassID) // 在建構時指定 ClassID
  {
  }

  // Destructor
  ~IVertexRD_T()
  {
  }
public:

  // 建立 IVertexRD_T 物件，失敗傳回 NULL
  // VertexID = 頂點資料識別
  static CxxlMan::Smart_Ptr<IVertexRD_T> cxxlFASTCALL Create(const CxxlMan::UNICODE_String &VertexID)
  {
    CxxlMan::Smart_Ptr<IVertexRD_T> r = CxxlMan::Preserve2_Cast<IVertexRD_T>( CxxlMan::cxxlCM_GetElement(IVertex_T_ClassID, IRenderDatagram_Group) );

    if(r.isNULL() == false)
      r->SysInit(VertexID);
    return r;
  }

  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<IVertexRD_T>;  // Preserve2 元件須加上這個
};


/********************************************/




}   /* namespace Cxxl3D */
#endif
